using System.Linq;
using Engine;
using Engine.OldSerialization;
using Game;

namespace RuthlessConquest {
    public class SpecialEventsModule : Module {
        public int NextEventStep;
        public int LastEventStep;
        public bool FirstEventHappened;
        public const string fName = "RCSpecialEventsModule";

        public SpecialEventsModule(Game game) : base(game) { }

        public override void Serialize(InputArchive archive) {
            archive.Serialize("NextEventStep", ref NextEventStep);
        }

        public override void Serialize(OutputArchive archive) {
            archive.Serialize("NextEventStep", NextEventStep);
        }

        public void Step() {
            if (NextEventStep == 0) {
                LastEventStep = StepModule.StepIndex;
                NextEventStep = StepModule.StepIndex + Game.CreationParameters.SpecialEventsPeriod * StepModule.Random.Int(20, 40) / 10 * 60;
            }
            if (SettingsManager.DisplayMoreNotices) {
                if (FirstEventHappened) {
                    if (StepModule.StepIndex - LastEventStep == Game.CreationParameters.SpecialEventsPeriod * 15 / 10 * 60 - 1) {
                        Game.Screen.MessagesListWidget.AddMessage(
                            string.Format(LanguageControl.Get(fName, "5"), Game.CreationParameters.SpecialEventsPeriod * 5 / 10),
                            Color.LightGray,
                            true
                        );
                    }
                }
                else {
                    if (StepModule.StepIndex - LastEventStep == Game.CreationParameters.SpecialEventsPeriod * 20 / 10 * 60 - 1) {
                        Game.Screen.MessagesListWidget.AddMessage(
                            string.Format(LanguageControl.Get(fName, "5"), Game.CreationParameters.SpecialEventsPeriod * 20 / 10),
                            Color.LightGray,
                            true
                        );
                    }
                }
            }
            if (StepModule.StepIndex >= NextEventStep) {
                if (StepModule.Random.Int() % 2 == 0) {
                    SendAliens();
                }
                else {
                    SendReinforcements();
                }
                FirstEventHappened = true;
                LastEventStep = StepModule.StepIndex;
                NextEventStep = StepModule.StepIndex + Game.CreationParameters.SpecialEventsPeriod * StepModule.Random.Int(15, 20) / 10 * 60;
            }
        }

        public void SendAliens() {
            int num = MathUtils.Clamp(StepModule.Random.Int(PlanetsModule.Planets.Count / 12, PlanetsModule.Planets.Count / 6), 1, 5);
            DynamicArray<Faction> dynamicArray = (from p in PlayersModule.Players
                where p.Status == FactionStatus.Undecided
                select p.Faction
                into f
                orderby GetFactionStrength(f) descending
                select f).ToDynamicArray();
            if (dynamicArray.Count <= 0) {
                return;
            }
            Faction faction = dynamicArray[0];
            DynamicArray<Planet> dynamicArray2 = new();
            for (int i = 0; i < 1000; i++) {
                if (dynamicArray2.Count >= num) {
                    break;
                }
                Planet planet = PlanetsModule.Planets[StepModule.Random.Int(PlanetsModule.Planets.Count)];
                if (planet.Faction == faction
                    && planet.SizeClass >= 1
                    && !dynamicArray2.Contains(planet)
                    && PlanetsModule.GetFactionPlanetsCount(faction) - dynamicArray2.Count - 1 > dynamicArray2.Count) {
                    dynamicArray2.Add(planet);
                }
            }
            if (dynamicArray2.Count <= 0) {
                return;
            }
            int factionStrength = GetFactionStrength(faction);
            int num2 = dynamicArray.Where(f => f != faction).Sum(f => GetFactionStrength(f)) / (dynamicArray.Count - 1);
            int num3 = factionStrength * Game.CreationParameters.AliensFactors.X / 100;
            int num4 = -num2 * Game.CreationParameters.AliensFactors.Y / 100;
            int z = Game.CreationParameters.AliensFactors.Z;
            int num5 = MathUtils.Clamp(num3 + num4 + z, 150, 700);
            int totalShipsCount = 0;
            foreach (Planet item in dynamicArray2) {
                int shipsCount = num5 / dynamicArray2.Count;
                totalShipsCount += shipsCount;
                ShipsModule.SendOutsideShips(Faction.Neutral, item, shipsCount);
            }
            Game.Screen.AliensAttackMessageWidget.SetMessage(
                SettingsManager.DisplayMoreNotices ? string.Format(LanguageControl.Get(fName, "3"), totalShipsCount) : LanguageControl.Get(fName, "1")
            );
            AudioManager.PlaySound(Sounds.Aliens, false);
        }

        public void SendReinforcements() {
            DynamicArray<Faction> dynamicArray = (from p in PlayersModule.Players
                where p.Status == FactionStatus.Undecided
                select p.Faction
                into f
                orderby GetFactionStrength(f)
                select f).ToDynamicArray();
            if (dynamicArray.Count >= 2) {
                Faction faction = dynamicArray[0];
                DynamicArray<Planet> dynamicArray2 = PlanetsModule.Planets.Where(p => p.Faction == faction).ToDynamicArray();
                Planet destination = dynamicArray2.Count <= 0
                    ? PlanetsModule.Planets[StepModule.Random.Int(PlanetsModule.Planets.Count)]
                    : dynamicArray2[StepModule.Random.Int(dynamicArray2.Count)];
                int factionStrength = GetFactionStrength(faction);
                int num = dynamicArray.Where(f => f != faction).Sum(f => GetFactionStrength(f)) / (dynamicArray.Count - 1);
                int num2 = factionStrength * Game.CreationParameters.ReinforcementsFactors.X / 100;
                int num3 = -num * Game.CreationParameters.ReinforcementsFactors.Y / 100;
                int z = Game.CreationParameters.ReinforcementsFactors.Z;
                int shipsCount = MathUtils.Clamp(num2 + num3 + z, 150, 700);
                ShipsModule.SendOutsideShips(faction, destination, shipsCount);
                Game.Screen.ReinforcementsMessageWidget.SetMessage(
                    faction,
                    SettingsManager.DisplayMoreNotices ? string.Format(LanguageControl.Get(fName, "4"), shipsCount) : LanguageControl.Get(fName, "2")
                );
                AudioManager.PlaySound(Sounds.Reinforcements, false);
            }
        }

        public int GetFactionStrength(Faction faction) {
            int period = Game.CreationParameters.PlanetValue * 60;
            return ShipsModule.FactionOwnShips[(int)faction]
                + PlanetsModule.FactionOwnPlanets[(int)faction]
                    .Sum(p => p.ShipsCount + period / p.ProductionPeriod + p.Satellites.Count * Game.CreationParameters.SatelliteValue);
        }
    }
}